import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;


//this class is to be attached to a folder such as private folder of ali
public class FileSystem {
	private String path;
	private File folder;
	private File[] listOfFiles;
	Path path2;
	
	private static String stopper = "-1uniqueidentifier";
	private static String stopper2 = "-1uniqueidentifier2";
	private static String stopper3 = "-1uniqueidentifier3";
	private static String invalidatedFileName = "-naim-naim-naim";
	private static String fileName = "-trollf-trollf-trollf";
	
	//OutputStream out;

	
	//those variables are to detect changes on files
	private ArrayList<String> fileList;
	private ArrayList<Long> lastModified;
	private ArrayList<Long> fileSize;
	private int fileLength;
	
	
	public FileSystem(String p) throws IOException
	{
		
		path = p;
		folder = new File(path);
		listOfFiles = folder.listFiles();
		
		try
		{
			read();
		}catch(Exception e)
		{
			
			correct();
		}
	}
	
	//check if the folder is empth or not -> for first time share only
	public boolean isEmpty() 
	{
		return (listOfFiles.length == 0);
	}
	
	private void write() throws IOException
	{
		//File file2 = new File();
	    BufferedWriter writer = new BufferedWriter(new FileWriter(path + "\\" + invalidatedFileName)); 
	   while(fileList.iterator().hasNext())
	   {
		    writer.write(fileList.iterator().next());
		    writer.newLine();
	   }
	   
	   writer.write(stopper);
	    writer.newLine();
	   
	   while(lastModified.iterator().hasNext())
	   {
		    writer.write(lastModified.iterator().next().toString());
		    writer.newLine();
	   }
	   
	   writer.write(stopper2);
	    writer.newLine();
	   
	   while(fileSize.iterator().hasNext())
	   {
		    writer.write(fileSize.iterator().next().toString());
		    writer.newLine();
	   }
	   
	   writer.write(stopper3);
	   writer.newLine();
	   
	    
	    writer.write(fileLength);
	    writer.newLine();
	    
	    writer.close();
	    
	    Files.move(	Paths.get(folder.getAbsolutePath() + "\\" + invalidatedFileName), 
				Paths.get(folder.getAbsolutePath() + "\\" + fileName), 
				StandardCopyOption.ATOMIC_MOVE,
				StandardCopyOption.REPLACE_EXISTING);
	}
	
	private void read() throws IOException
	{
		
		 boolean st = true;
		 boolean st2 = true;
		 boolean st3 = true;
		 String line;
		 BufferedReader in = new BufferedReader(new FileReader(path+ "\\" + fileName)); 
		 while ((line = in.readLine()) != null) {
			 if(!line.equals(stopper) && st)
			 {
				 fileList.add(line);
				 continue;
			 } else if(st)
			 {
				 st = false;
				 continue;
			 }
				 
			 if(!line.equals(stopper2) && st2)
			 {
				 lastModified.add(Long.parseLong(line));
				 continue;
			 }else if(st2)
			 {
				 st2 = false;
				 continue;
			 }
			 
			 if(!line.equals(stopper3) && st3)
			 {
				 fileSize.add(Long.parseLong(line));
				 continue;
			 }else if(st3)
			 {
				 st3 = false;
				 continue;
			 }

			 fileLength = Integer.parseInt(line);
		 }
		 in.close();
	}
	
	// checks if any of the files are changed since last change
	public boolean isChanged()
	{
		File folder2;
		folder2 = new File(path);
		File[] listOfFiles2;
		listOfFiles2 = folder2.listFiles();

		if(fileLength != listOfFiles2.length) // compare number of files
			return true;
		
		for(int i = 0; i < listOfFiles2.length; i++) // compare names
		{
			int k = position(listOfFiles2[i].getName());
			if(k == -1)
			{
				return true;
			} else if(listOfFiles2[i].lastModified() != lastModified.get(i))
				return true;
			else if (listOfFiles2[i].length() != fileSize.get(i))
				return true;
		}
		return false;
	}

	// checks if any extra file is added or modified in the new version
	// and sends as a string arraylist
	public ArrayList<String> changedList() 
	{
		File folder2;
		folder2 = new File(path);
		File[] listOfFiles2;
		listOfFiles2 = folder2.listFiles();
		ArrayList<String> newList = new ArrayList<String>(); //those files need to be downloaded again

		
		for(int i = 0; i < listOfFiles2.length; i++) // compare names
		{
			int k = position(listOfFiles2[i].getName());
			if(k == -1)
			{
				newList.add(listOfFiles2[i].getName());	
			} else if(listOfFiles2[i].lastModified() !=lastModified.get(i))
				newList.add(listOfFiles2[i].getName());
			else if(listOfFiles2[i].length() != fileSize.get(i))
				newList.add(listOfFiles2[i].getName());
		}
		return newList;
	}

	// checks if any file is removed in the new version
	// and sends as a string arraylist
	public ArrayList<String> removedList() 
	{
		File folder2;
		folder2 = new File(path);
		File[] listOfFiles2;
		listOfFiles2 = folder2.listFiles();
		ArrayList<String> removeList = new ArrayList<String>(); //those files need to be downloaded again

		
		for(int i = 0; i < fileList.size(); i++) // compare names
		{
			int mkj = -1;
			for (int q = 0; q < listOfFiles2.length; q++)
			{
				if (listOfFiles2[q].getName().equals(fileList.get(i))) 
				{
					mkj = q;
				}
			}
			if(mkj == -1)
			{
				removeList.add(fileList.get(i));
			}
		}
		return removeList;
	}
	
	
	public ArrayList<String> getAll()
	{
		//ArrayList<String> allList = new ArrayList<String>();
		ArrayList<String> allList = this.changedList(); 
		ArrayList<String> delList = this.removedList(); 
		while(delList.iterator().hasNext())
			allList.add(delList.iterator().next());
		return allList;
	}

	// after list is changed, you must UPDATE IT manually by invoking this method !!!!
	public void update() throws IOException
	{
		File folder2;
		folder2 = new File(path);
		File[] listOfFiles2;
		listOfFiles2 = folder.listFiles();
		listOfFiles = listOfFiles2;
		folder = folder2;
		correct();
	}
	
	// prints the files in the current directory
	public void dir()
	{
		String files;
		for (int i = 0; i < listOfFiles.length; i++) 
		{
			if (listOfFiles[i].isFile()) 
			{
				files = listOfFiles[i].getName();
				System.out.println(files);
			}
		}
	}

	// returns absoulte path of a file
	public String getFile(String filename)
	{
		for (int i = 0; i < listOfFiles.length; i++)
			if (filename.equals(listOfFiles[i].getName()))
				return listOfFiles[i].getAbsolutePath();
		return null;
	}
	
	// returns absoulte path of the current folder
	public String getDirectory()
	{
		return folder.getAbsolutePath();
	}
	
	//part of update
	private void correct() throws IOException
	{
		fileList = new ArrayList<String>();
		lastModified = new  ArrayList<Long>();
		fileSize = new  ArrayList<Long>();
		//filelist.add(listOfFiles.toString());
		for (int i = 0; i < listOfFiles.length; i++) 
		{
			if (listOfFiles[i].isFile()) 
			{
				fileList.add(listOfFiles[i].getName());
				lastModified.add(listOfFiles[i].lastModified());
				fileSize.add(listOfFiles[i].length());
			}
		}
		fileLength = fileList.size();
		write();
		
	//	System.out.println("filesystem object created");
	}
	
	public ArrayList<String> getFileList() {
		return fileList;
	}
	
	public ArrayList<Long> modifiedList() {
		return lastModified;
	}
	
	public ArrayList<Long> getfileSize() {
		return fileSize;
	}

	public int getFileLength() {
		return fileLength;
	}
	
	private int position(String filename)
	{
		for (int i = 0; i < fileList.size(); i++) 
		{
			if (filename.equals(fileList.get(i))) 
			{
				return i;
			}
		}
		return -1;
	}
}
